package com.it.common.utils;


import com.nimbusds.jose.JOSEObjectType;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSVerifier;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jose.crypto.MACVerifier;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * JWT工具类 (使用 Nimbus JOSE + JWT 库)
 */
@Slf4j
public class JwtUtils {

    /**
     * 密钥 (必须是至少 256 位的随机字符串)  <br>
     * **重要：** 在生产环境中，请使用更安全的方式存储和管理密钥。
     */
    private static final String SECRET = "your-very-strong-secret-key-that-is-at-least-256-bits-long"; // 替换为你自己的密钥

    /**
     * 过期时间（单位：秒）
     */
    private static final long EXPIRATION = 24 * 60 * 60;

    /**
     * 生成token
     *
     * @param userId 用户ID
     * @return token
     */
    public static String generateToken(Long userId) {
        return generateToken(userId, null);
    }

    /**
     * 生成token
     *
     * @param userId 用户ID
     * @param
     * @return token
     */
    public static String generateToken(Long userId, Map<String, Object> customClaims) {
        try {
            // 1. 创建 JWT claims
            JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
                    .jwtID(UUID.randomUUID().toString())
                    .issuer("heima-leadnews") // 可选
                    .issueTime(new Date())
                    .expirationTime(Date.from(Instant.now().plus(EXPIRATION, ChronoUnit.SECONDS)))
                    .subject(userId.toString())
                    .claim("userId", userId) // 标准声明之外，添加 userId
                    .build();

            // 2. 创建 JWSHeader
            JWSHeader jwsHeader = new JWSHeader.Builder(JWSAlgorithm.HS256).type(JOSEObjectType.JWT).build();

            // 3. 创建 SignedJWT 对象
            SignedJWT signedJWT = new SignedJWT(jwsHeader, claimsSet);

            // 4. 签名
            MACSigner signer = new MACSigner(SECRET.getBytes());
            signedJWT.sign(signer);

            // 5. 序列化
            return signedJWT.serialize();

        } catch (Exception e) {
            log.error("JWT生成失败", e);
            return null;
        }
    }

    /**
     * 验证token
     *
     * @param token token
     * @return 是否有效
     */
    public static boolean validateToken(String token) {
        if (StringUtils.isBlank(token)) {
            return false;
        }
        try {
            SignedJWT signedJWT = SignedJWT.parse(token);
            JWSVerifier verifier = new MACVerifier(SECRET.getBytes());

            return signedJWT.verify(verifier);  // 验证签名

        } catch (Exception e) {
            log.error("JWT验证失败", e);
            return false;
        }
    }

    /**
     * 从token中获取用户ID
     *
     * @param token token
     * @return 用户ID
     */
    public static Long getUserIdFromToken(String token) {
        if (StringUtils.isBlank(token)) {
            return null;
        }
        try {
            SignedJWT signedJWT = SignedJWT.parse(token);
            JWTClaimsSet claims = signedJWT.getJWTClaimsSet();
            return Long.valueOf(claims.getClaim("userId").toString());
        } catch (Exception e) {
            log.error("从JWT获取用户ID失败", e);
            return null;
        }
    }

    /**
     * 从token中获取claim
     *
     * @param token token
     * @param key   key
     * @return value
     */
    public static Object getClaimFromToken(String token, String key) {
        if (StringUtils.isBlank(token)) {
            return null;
        }
        try {
            SignedJWT signedJWT = SignedJWT.parse(token);
            JWTClaimsSet claims = signedJWT.getJWTClaimsSet();
            return claims.getClaim(key);
        } catch (Exception e) {
            log.error("从JWT获取claim失败", e);
            return null;
        }
    }

    /**
     * 从token中获取所有claims
     *
     * @param token token
     * @return claims
     */
    public static Map<String, Object> getAllClaimsFromToken(String token) {
        if (StringUtils.isBlank(token)) {
            return null;
        }
        try {
            SignedJWT signedJWT = SignedJWT.parse(token);
            JWTClaimsSet claims = signedJWT.getJWTClaimsSet();
            return claims.getClaims(); //  返回所有声明
        } catch (Exception e) {
            log.error("从JWT获取所有claims失败", e);
            return null;
        }
    }
}